package com.yuyou.hxyy.service.api.service.impl;

import com.alibaba.fastjson.JSON;
import com.yuyou.hxyy.service.api.bean.Pagination;
import com.yuyou.hxyy.service.api.entity.*;
import com.yuyou.hxyy.service.api.enums.CategoryEnum;
import com.yuyou.hxyy.service.api.enums.CommEnums;
import com.yuyou.hxyy.service.api.exception.BusinessException;
import com.yuyou.hxyy.service.api.mapper.*;
import com.yuyou.hxyy.service.api.service.IWordRepoService;
import com.yuyou.hxyy.service.api.service.IWordUnitService;
import com.yuyou.hxyy.service.api.util.DateUtil;
import com.yuyou.hxyy.service.api.util.DefindBeanUtils;
import com.yuyou.hxyy.service.api.util.Sequence;
import com.yuyou.hxyy.service.api.vo.req.WordUnitExcel;
import com.yuyou.hxyy.service.api.vo.resp.WordUnitStatisticsVo;
import com.yuyou.hxyy.service.api.vo.resp.WordUnitVo;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
public class WordUnitServiceImpl implements IWordUnitService {

    @Autowired
    private WordUnitMapper mapper;

    @Autowired
    private IWordRepoService wordRepoService;

    @Autowired
    private WordRepoMapper wordRepoMapper;

    @Autowired
    private WordMapper wordMapper;

    @Autowired
    private DataImportMapper dataImportMapper;

    @Autowired
    private UserWordRepoMapper userWordRepoMapper;

    @Autowired
    private UserWordUnitMapper userWordUnitMapper;

    @Override
    public int deleteByPrimaryKey(Long WordUnit) {
        return mapper.deleteByPrimaryKey(WordUnit);
    }

    @Override
    public int insert(WordUnit record) {
        return mapper.insert(record);
    }

    @Override
    @Transactional
    public void insertWordUnit(String name, Long wordRepoId, Integer category, Long userId , Integer sort) {
        WordUnit w = new WordUnit();
        if(sort == null){
            sort = mapper.getMaxSort(wordRepoId);//获取最大序号
            sort = sort == null ? 1:sort+1;
        }
        w.setWordUnitId(Sequence.getSequence().nextId());
        w.setName(name);
        w.setWordRepoId(wordRepoId);
        w.setIsDel(0);
        w.setIsLeaf(1);
        w.setLevel(1);
        w.setCreateTime(new Date());
        w.setCreateUser(userId);
        w.setSort(sort);
        insert(w);
    }

    @Override
    @Transactional
    public void updateWordUnit(String name, Long id, Long userId , Integer sort) {
        WordUnit old = selectByPrimaryKey(id);
        if(old == null){return ; }
        WordUnit other = findByNameRepo(old.getWordRepoId() , name);
        if(other != null && !other.getWordUnitId().equals(old.getWordUnitId())){//该词典已存在该名称的关卡
            throw new BusinessException("该词典已存在该名称的关卡");
        }
        WordUnit w = new WordUnit();
        w.setWordUnitId(id);
        w.setName(name);
        w.setUpdateTime(new Date());
        w.setUpdateUser(userId);
        if(sort != null){w.setSort(sort);}
        updateByPrimaryKeySelective(w);
    }

    @Override
    public WordUnit selectByPrimaryKey(Long WordUnit) {
        return mapper.selectByPrimaryKey(WordUnit);
    }

    @Override
    public int updateByPrimaryKeySelective(WordUnit record) {
        return mapper.updateByPrimaryKeySelective(record);
    }

    @Override
    @Transactional
    public void deleteByIds(String ids) {
        List<Long> repoIds = wordRepoMapper.findRepoIdsByUnitIds(ids);//查询出关卡对应的词典ids
        mapper.deleteByIds(ids);
        wordMapper.deleteByUnitIds(ids);
        userWordUnitMapper.deleteByUnitIds(ids);
        if(!CollectionUtils.isEmpty(repoIds)){
            List<Long> delIds = userWordRepoMapper.getIdByWordUtil(ids ,repoIds);//清空多余词典学习记录
            for (Long id :
                    delIds) {
                userWordRepoMapper.deleteByPrimaryKey(id);
            }
            //更改变成已学习状态的学生词典学习记录
            for (Long repoId :
                    repoIds) {
                List<Long> userIds = userWordRepoMapper.getNotUpdatedUserRepo(repoId);//获取变成已完成学习的学生列表
                if(!CollectionUtils.isEmpty(userIds)){
                    userWordRepoMapper.updateStatusByrepoIdUserIds(repoId , userIds);//通过学生id和词典id更新
                }
            }
        }
    }

    @Override
    public int findWordUnitCount(Pagination<WordUnitVo> queryPgn) {
        return mapper.findWordUnitCount(queryPgn);
    }

    @Override
    public List<WordUnitVo> findWordUnitPage(Pagination<WordUnitVo> queryPgn) {
        List<WordUnitVo> list = mapper.findWordUnitPage(queryPgn);
        for (WordUnitVo w :
                list) {
            if(w.getCategory() != null){
                switch (w.getCategory()){
                    case 2:
                        w.setCategaryName(CategoryEnum.Category.HIGH_SCHOOL.getName());
                        break;
                    case 1:
                        w.setCategaryName(CategoryEnum.Category.MIDDLE_SCHOOL.getName());
                        break;
                    case 0:
                        w.setCategaryName(CategoryEnum.Category.PRIMARY_SCHOOL.getName());
                        break;
                    default:
                        w.setCategaryName("");
                }
            }
        }
        return list;
    }

    @Override
    public List<WordUnitVo> findAllWordUnit(Map<String, Object> condition) {
        return mapper.findAllWordUnit(condition);
    }

    @Override
    public WordUnit findByNameRepo(Long repoId, String name) {
        return mapper.findByNameRepo(repoId , name);
    }


    @Override
    @Transactional
    public DataImport saveWordUnitImport(List<WordUnitExcel> wordUnitExcelList) {

        int total = wordUnitExcelList.size();
        // 有问题的数据不导入
        List<WordUnitExcel> failWordUnitList = checkWordUnitImport(wordUnitExcelList);
        List<WordUnit> wordUnitList = new ArrayList<>(wordUnitExcelList.size());
        for(WordUnitExcel wordUnitExcel : wordUnitExcelList){
            WordUnit wordUnit = new WordUnit();
            wordUnit.setWordUnitId(Sequence.getSequence().nextId());
            wordUnit.setWordRepoId(wordUnitExcel.getWordRepoId());
            wordUnit.setName(wordUnitExcel.getWordUnit());
            wordUnit.setIsLeaf(CommEnums.isLeaf.yes.getValue());
            wordUnit.setSort(wordUnitExcel.getSort());
            wordUnit.setLevel(1);
            wordUnit.setIsDel(CommEnums.isDel.no.getValue());
            wordUnit.setUpdateTime(DateUtil.now());
            wordUnit.setCreateTime(DateUtil.now());
            wordUnitList.add(wordUnit);
        }

        // 批量插入关卡
        if(!CollectionUtils.isEmpty(wordUnitList)){
            mapper.batchInsertWordUnit(wordUnitList);
        }

        /** 导入成败记录 */
        DataImport dataImport = new DataImport();
        dataImport.setId(Sequence.getSequence().getNextId());
        dataImport.setTotal(total);
        dataImport.setSuccNum(wordUnitList.size());
        dataImport.setFailNum(failWordUnitList.size());
        dataImport.setStatus(failWordUnitList.size() > 0 ? "1" : "0");
        dataImport.setType(CommEnums.resourceType.wordUnit.getValue());
        dataImport.setContent(JSON.toJSONString(failWordUnitList));
        dataImport.setCreateTime(DateUtil.now());
        dataImportMapper.insert(dataImport);

        return dataImport;
    }

    @Override
    public List<WordUnitStatisticsVo> getUnitList(Long repoId , Long userId) {
        return mapper.getUnitList(repoId,userId);
    }

    @Override
    @Transactional
    public void passUnit(Long wordRepoId, Long wordUnitId, Long userId) {
        if(userWordUnitMapper.getByRepoUnitUserId(wordRepoId,wordUnitId,userId) != null){//已存在记录
            return;
        }
        UserWordUnit userWordUnit = new UserWordUnit();
        userWordUnit.setUserWordUnitId(Sequence.getSequence().nextId());
        userWordUnit.setCreateTime(new Date());
        userWordUnit.setAuthUserId(userId);
        userWordUnit.setWordRepoId(wordRepoId);
        userWordUnit.setWordUnitId(wordUnitId);
        userWordUnit.setStatus(1);
        userWordUnitMapper.insert(userWordUnit);


        int status = 1;//默认进行中

        //总关卡数
        Integer unitCount = mapper.findWordUnitCountByRepo(wordRepoId);
        //已学关卡数
        Integer learnedUnitCount = userWordUnitMapper.getLearnedCountByRepo(wordRepoId , userId);
        if(unitCount == learnedUnitCount){status = 2;}//已学完

        UserWordRepo userWordRepo = userWordRepoMapper.getByRepoUserId(wordRepoId ,userId);
        if(userWordRepo == null){
            userWordRepo = new UserWordRepo();
            userWordRepo.setUserWordRepoId(Sequence.getSequence().nextId());
            userWordRepo.setWordRepoId(wordRepoId);
            userWordRepo.setAuthUserId(userId);
            userWordRepo.setCreateTime(new Date());
            userWordRepo.setStatus(status);
            userWordRepoMapper.insert(userWordRepo);
        }else if(status == 2){
            userWordRepo.setStatus(2);
            userWordRepoMapper.updateByPrimaryKeySelective(userWordRepo);
        }

    }


    private List<WordUnitExcel> checkWordUnitImport(List<WordUnitExcel> wordUnitExcelList) {
        // 导入失败的关卡
        List<WordUnitExcel> failWordUnitList = new ArrayList<>();
        Iterator<WordUnitExcel> iterator = wordUnitExcelList.iterator();
        Set<String> wordUnitSet = new HashSet<>();
        while (iterator.hasNext()) {
            WordUnitExcel wordUnitExcel = iterator.next();
            WordUnitExcel failWordUnit = new WordUnitExcel();
            DefindBeanUtils.copyProperties(wordUnitExcel, failWordUnit);
            StringBuilder failReason = new StringBuilder();

            List<String> categoryList = Arrays.asList("小学", "初中", "高中");

            if (StringUtils.isEmpty(wordUnitExcel.getWordUnit())) {
                failReason.append(";").append("关卡为空");
            } else if (wordUnitExcel.getWordUnit().trim().length() > 100) {
                failReason.append(";").append("关卡长度大于100");
            } else if (wordUnitSet.contains(wordUnitExcel.getWordUnit().trim()+wordUnitExcel.getWordRepo().trim())) {
                failReason.append(";").append("导入文件中该关卡已经存在");
            } else if (StringUtils.isEmpty(wordUnitExcel.getWordRepo())) {
                failReason.append(";").append("词库为空");
            } else if (wordUnitExcel.getWordRepo().trim().length() > 100) {
                failReason.append(";").append("词库长度大于100");
            } else if (StringUtils.isEmpty(wordUnitExcel.getCategory())) {
                failReason.append(";").append("类别为空");
            } else if (!categoryList.contains(wordUnitExcel.getCategory())) {
                failReason.append(";").append("类别有误");
            }else if (null == wordUnitExcel.getSort()) {
                failReason.append(";").append("序号为空");
            }

            WordRepo wordRepo = wordRepoService.findByNameCategory(wordUnitExcel.getWordRepo().trim(),
                    ("小学".equals(wordUnitExcel.getCategory()) ? 0 : ("初中".equals(wordUnitExcel.getCategory()) ? 1 : 2)));

            if (null == wordRepo) {
                failReason.append(";").append("词库不存在");
            } else if (null != findByNameRepo(wordRepo.getWordRepoId(), wordUnitExcel.getWordUnit().trim())) {
                failReason.append(";").append("关卡已经存在");
            } else {
                wordUnitExcel.setWordRepoId(wordRepo.getWordRepoId());
                wordUnitSet.add(wordUnitExcel.getWordUnit().trim()+wordUnitExcel.getWordRepo().trim());
            }

            // 不符合的，移除不导入
            if (!StringUtils.isEmpty(failReason.toString())) {
                failWordUnit.setFailedReason(failReason.toString().substring(1, failReason.toString().length()));
                failWordUnitList.add(failWordUnit);
                iterator.remove();
            }
        }
        return failWordUnitList;
    }

    @Override
    public XSSFWorkbook failedInfoOfWordUnitImport(List<WordUnitExcel> wordUnitExcelList){

        XSSFWorkbook excel = new XSSFWorkbook();

        XSSFSheet sheet = excel.createSheet("导入失败信息");

        XSSFRow firstRow = sheet.createRow(0);

        String[] titles = new String[] { "关卡","词库","类别","序号","导入失败原因"};

        for (int i = 0; i < titles.length; i++) {
            XSSFCell cell = firstRow.createCell(i);

            // 失败原因设置为红色
            if(i == titles.length -1){
                XSSFCellStyle cellStyle = excel.createCellStyle();
                cellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
                cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
                cell.setCellStyle(cellStyle);
            }
            cell.setCellValue(titles[i]);
        }

        for (int i = 0; i < wordUnitExcelList.size(); i++ ) {

            WordUnitExcel wordUnitExcel = wordUnitExcelList.get(i);

            XSSFRow row = sheet.createRow(i + 1);

            int c = 0;
            XSSFCell cell = row.createCell(c++);
            cell.setCellValue(wordUnitExcel.getWordUnit());

            cell = row.createCell(c++);
            cell.setCellValue(wordUnitExcel.getWordRepo());

            cell = row.createCell(c++);
            cell.setCellValue(wordUnitExcel.getCategory());

            cell = row.createCell(c++);
            cell.setCellValue(null == wordUnitExcel.getSort() ? "" : wordUnitExcel.getSort().toString());

            cell = row.createCell(c++);
            // 失败原因设置为红色
            XSSFCellStyle cellStyle = excel.createCellStyle();
            cellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
            cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
            cell.setCellStyle(cellStyle);
            cell.setCellValue(wordUnitExcel.getFailedReason());
        }
        return excel;
    }

    @Override
    public WordUnitStatisticsVo getStuNextUnitId(Long unitId, Long userId) {
        WordUnit wordUnit = mapper.selectByPrimaryKey(unitId);
        if(wordUnit != null){
            boolean found = false;
            WordUnitStatisticsVo wordUnitStatisticsVo = null;
            List<WordUnitStatisticsVo> list = getUnitList(wordUnit.getWordRepoId() , userId);
            for (WordUnitStatisticsVo w :
                    list) {
                if(found  &&  w.getWordCount() != null && w.getWordCount() > 0){
                    wordUnitStatisticsVo = w;
                    break;
                }
                if(w.getId().equals(unitId)){
                    found = true;
                }
            }
            return wordUnitStatisticsVo;
        }

        return null;
    }
}
